package com.ticker.national.util;

import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.http.AndroidHttpClient;
import android.os.AsyncTask;
import android.os.Environment;
import android.os.Handler;

import com.ticker.national.util.HtmlParsing.TaskType;


public class ImageDownloaderTask extends AsyncTask<Handler, Void, Bitmap> {
	
	private final String TAG = "ImageDownloaderTask";
	
	private String mUrl;
	private Handler mHandler;
	
	private HashMap<String, Bitmap> mBitmapMap;
	private TaskType mType;
	
	private int mErrorCount;
	private int mId;

	public ImageDownloaderTask(HashMap<String, Bitmap> bitmap, String url, TaskType type) {
		mErrorCount = 0;
		mId = this.hashCode();
		mUrl = url;
		mBitmapMap = bitmap;
		mType = type;
	}
	
	public int getId() {
		return mId;
	}
	
	@Override
	protected Bitmap doInBackground(Handler... params) {
		
		//TODO replace
		if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
			Log.e(TAG, "MEDIA DIDN'T MOUNT!!");
			return null;
		}
		
		if (params[0] instanceof Handler) {
			mHandler = (Handler) params[0];
		}
		
		if(mUrl == null) {
			Log.e("Url is null", new NullPointerException("Url is null"));
		}
		
		Bitmap bitmap = null;
		bitmap = downloadBitmap(mUrl, mType);
		
		return bitmap;
	}
	
	
	
	@Override
	protected void onPostExecute(Bitmap result) {
		onFinish(result);
		mHandler.sendEmptyMessage(mId);
	}

	private void onFinish(Bitmap result) {
		
		if(result == null) 
			Log.e(TAG, "onFinish(), error");
		
		mBitmapMap.remove(mUrl);
		mBitmapMap.put(mUrl, result);
	}

	Bitmap downloadBitmap(String url, TaskType type) {
		Log.d(TAG, "downloadBitmap, url: " + url);
		Log.d(TAG, "mErrorCount: " + mErrorCount);
		
		final HttpClient client = AndroidHttpClient.newInstance(this.getClass().getName());
		HttpGet getRequest = new HttpGet(url);
		BitmapFactory.Options options = new BitmapFactory.Options();
		int statusCode = 0;
		
		if(type == TaskType.ProfileImage) {
			options.inSampleSize = 2;
		}
		else if(type == TaskType.LocationImage) {
			options.inSampleSize = 4;
		}
		
		try {
			HttpResponse response = client.execute(getRequest);
			statusCode = response.getStatusLine().getStatusCode();
			if(statusCode != HttpStatus.SC_OK) {
				Log.e("statusCode : " + statusCode);
				if(statusCode == HttpStatus.SC_MOVED_TEMPORARILY) {
					url = response.getLastHeader("Location").getValue();
					throw new RedirectException();
				}
			}
			
			final HttpEntity entity = response.getEntity();
			if(entity != null) {
				Log.d(TAG, "entity: " + entity.toString());
				InputStream inputStream = null;
				
				try {
					inputStream = entity.getContent();
					Bitmap bitmap = BitmapFactory.decodeStream(new FlushedInputStream(inputStream), null, options);
					return bitmap;
				} finally {
					if(inputStream != null) {
						inputStream.close();
					}
					entity.consumeContent();
				}
			}
			
		} catch (ClientProtocolException e) {
			Log.e("Error : ClientProtocolException()");
			getRequest.abort();
			e.printStackTrace();
			mErrorCount++;
			
			if(mErrorCount < 5)
				return downloadBitmap(url, type);
			
		} catch (IOException e) {
			Log.e("ImageDownloaderTask, Error : IOException()");
			getRequest.abort();
			e.printStackTrace();
			mErrorCount++;
			
			if(mErrorCount < 5)
				return downloadBitmap(url, type);
			
		} catch (RedirectException e) {
			Log.e("ImageDownloaderTask, RedirectException()");
			e.printStackTrace();
		} finally {
			if(client instanceof AndroidHttpClient) {
				((AndroidHttpClient) client).close();
				getRequest 	= null;
				options 	= null;
			}
			if(statusCode == HttpStatus.SC_MOVED_TEMPORARILY)
				return downloadBitmap(url, type);
		}
		
		return null;
	}
	
    /*
     * An InputStream that skips the exact number of bytes provided, unless it reaches EOF.
     */
	class FlushedInputStream extends FilterInputStream {

		protected FlushedInputStream(InputStream inputStream) {
			super(inputStream);
		}

		@Override
		public long skip(long count) throws IOException {
			long totalBytesSkipped = 0L;
			
			while(totalBytesSkipped < count) {
				long bytesSkipped = in.skip(count - totalBytesSkipped);
				if(bytesSkipped == 0L) {
					int b = read();
					if(b < 0) {
						break;	// we reached EOF
					} else {
						bytesSkipped = 1;	// we read one byte
					}
				}
				totalBytesSkipped += bytesSkipped;
			}
			return totalBytesSkipped;
		}
	}
}
